# -*- coding: utf-8 -*-
# @Time : 2024/1/20 17:48
# @Author : cute
# @Email : Aggressive_cute@126.com
import execjs
from urllib.parse import urlencode
import os
import sys
import requests
import json
import random
import re
import hmac
import time
import hashlib
import requests
import execjs
import datetime
from loguru import logger
from curl_cffi import requests
from sanic import Blueprint
class Method:
    GET = 'GET'
    POST = 'POST'
def _request(method: str = 'GET', *args, **kwargs):
    """请求封装"""
    error_count = 0
    # 是否挂代理
    # if not self.proxies:
    #     headers, self.proxies = self.get_proxies(self.headers)
    kwargs.update(
        {
            'impersonate':'chrome107'
        }
    )
    while True:
        try:
            if error_count > 10:
                return

            if method == Method.GET:
                resp = requests.get(**kwargs)
            else:
                resp = requests.post(**kwargs)

            return resp

        except Exception as e:
            logger.error('_request error {}'.format(e))
            error_count += 1

def my_sha256(encrypt_data) -> str:
    """
    md5摘要算法加密
    :return:
    """
    obj = hashlib.sha256()
    obj.update(encrypt_data.encode('utf-8'))
    res = obj.hexdigest()
    return res


def dumps(data_dict):
    """
    字典数据序列化
    :return:
    """
    import json
    # return json.dumps(data_dict, separators=(',', ':'))
    return json.dumps(data_dict, separators=(',', ':'), ensure_ascii=False)

def get_current_timestamp13():
    """
    获取13位数时间戳
    :return:
    """
    return "{}".format(int(time.time() * 1000))

api = Blueprint('api', url_prefix='/api')

file_dir = os.path.join(os.getcwd(),'static','js')
encrypt_ctx = execjs.compile(open(os.path.join(file_dir,'aes.js'), encoding='utf-8').read())
hmac_ctx = execjs.compile(open(os.path.join(file_dir,'hmacEncrypt_4.7.3.js'), encoding='utf-8').read())
algo_encrypt_ctx = execjs.compile(open(os.path.join(file_dir,'algo_aes.js'), encoding='utf-8').read())


headers = {
    "accept": "application/json, text/javascript, */*; q=0.01",
    "accept-language": "zh-CN,zh;q=0.9",
    "cache-control": "no-cache",
    "origin": "https://item.jd.com",
    "pragma": "no-cache",
    "priority": "u=1, i",
    "referer": "https://item.jd.com/",
    "sec-ch-ua": "\"Google Chrome\";v=\"125\", \"Chromium\";v=\"125\", \"Not.A/Brand\";v=\"24\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-site",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
    "x-referer-page": "https://item.jd.com/100071377749.html",
    "x-rp-client": "h5_1.0.0"
}
cookies = {
    "3AB9D23F7A4B3CSS": "jdd03NPIEGMNR4F6EL5ULHXYHFFVB67PZV4QGPVVMJPENQFYHLCKIZMHXGBAS2VFN2N5XSOJR7UPMF4O2IUNG5BOKFMPCCIAAAAMQESBMQOIAAAAACJZ54XSJJ2TGU4X",
    "_gia_d": "1",
    "jsavif": "1",
    "__jdv": "181111935|direct|-|none|-|1718599468102",
    "shshshfpa": "f71de36c-ee08-6a41-f586-f6e9399a1df6-1718599468",
    "shshshfpx": "f71de36c-ee08-6a41-f586-f6e9399a1df6-1718599468",
    "__jdu": "17185994681021676403441",
    "areaId": "4",
    "ipLoc-djd": "4-48205-71418-0",
    "mba_muid": "17185994681021676403441",
    "mba_sid": "17185994702582930178025173675.1",
    "wlfstk_smdl": "6c0an17fzg5i7ge9e0h323fzh4e42uv9",
    "3AB9D23F7A4B3C9B": "NPIEGMNR4F6EL5ULHXYHFFVB67PZV4QGPVVMJPENQFYHLCKIZMHXGBAS2VFN2N5XSOJR7UPMF4O2IUNG5BOKFMPCCI",
    "TrackID": "1aUYEo648-Q6WdY89N2y1tHKvNJcJ4EwjCIUCYICCT-ruzh8mNHq9m-r1_uXH9TBua4vCZ8N6Mi39MHRCIlnvaOuSotBM7VeoX9LSQKxFeek",
    "thor": "535CF7E2F9DA3300484562302834CC48DA9E292B6470B218EB4522B624C0D8CADB8157A3D2D31E43FDAD40827D12B0469CB4996140C211815DA53497EE3DB61389A2E772A76637FB9470EB2ED19F867ED9CF0042BABE434B8C38091F14FB8C7A99E872F1E9A8BDB4518F5E5D2DAAD21761DE146795FDEE3F907D13E41F1CB9E90178443782FEFBD91FCC91F5AACC237F13988F53377D7BD11D7E4B27BFD6D818",
    "pinId": "VRPkdxsSV8eGYEG9t31I37V9-x-f3wj7",
    "pin": "jd_6cc2cec972b5b",
    "unick": "jd_k09g652vn75e2p",
    "ceshi3.com": "000",
    "_tp": "OxRjWkxGGlvSIQqfOjUCLiYzl0EcDaIWdQlkXSaBYC8%3D",
    "_pst": "jd_6cc2cec972b5b",
    "token": "f913b6f125df3f8d9af310b17216f36c,3,954777",
    "__tk": "efe3f4b96cd7bd140db7277738bdb68d,3,954777",
    "__jda": "181111935.17185994681021676403441.1718599468.1718599468.1718599468.1",
    "__jdc": "181111935",
    "shshshfpb": "BApXcyqaLJ_VA6018HE-E9UdPn56CXKwsBloYk0do9xJ1MvuEcoC2",
    "__jdb": "181111935.5.17185994681021676403441|1.1718599468",
    "flash": "2_peQCSdADe-uq-F91hxF-32BnPpMlaFPyrysSwyz_U5TGmxnmvps_VwDeDCQxdbHp4yalK8fQhPhFnUIsQiix_j6jXcCmH7tIwVlcE3mDLYwfWy4yX0wNCbAKSJC85OEYctloK6BHsMJBczwtcN3G4XEkM92pKaBz5g5AeaNklMk*"
}

def update_algo_4_7(algo_data_dict):
    """算法自动更新"""
    headers = {
        "accept": "application/json",
        "accept-language": "zh-CN,zh;q=0.9",
        "content-type": "application/json",
        "origin": "https://trade.m.jd.com",
        "priority": "u=1, i",
        "referer": "https://trade.m.jd.com/",
        "sec-ch-ua": "\"Google Chrome\";v=\"125\", \"Chromium\";v=\"125\", \"Not.A/Brand\";v=\"24\"",
        "sec-ch-ua-mobile": "?0",
        "sec-ch-ua-platform": "\"Windows\"",
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "same-site",
        "user-agent": algo_data_dict['ua']
    }
    rd_obj = re.compile("{var rd='(.*?)';var", re.S)
    algo_obj = re.compile("return algo.(.*?)\(", re.S)

    version = "4.7"
    platform = "web"
    pin = algo_data_dict['pin']
    fv = algo_data_dict['fv']
    fp = algo_data_dict['fingerprint']
    app_id = algo_data_dict['app_id']

    algo_global_this = {
        "_version": version,
        "version": fv,
        "_appId": app_id,
        "_fingerprint": fp,
        'sua': re.search(r"\((?P<sua>.*?)\)", headers['user-agent']).group('sua'),
        'iv': '0102030405060708',
        'key': 'wm0!@w-s#ll1flo(',
        'canvas': algo_data_dict['canvas'],
        "webglFp": algo_data_dict['webglFp'],
        'ua': headers["user-agent"],
        'av': headers["user-agent"].replace('Mozilla/', ''),
        'pin': pin
    }

    def get_env_str(fv, fp, app_id):
        """各种指纹+AES-CBC 验证ok 魔改版本"""
        # 指纹信息
        random_val = ''.join(random.choices("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-", k=12))
        plaintext_dict = {
            "wc": 0,
            "wd": 0,
            "l": "zh-CN",
            "ls": "zh-CN,zh",
            "ml": 2,
            "pl": 5,
            "av": algo_global_this['av'],
            "ua": algo_global_this['ua'],
            "sua": algo_global_this['sua'],
            "pp": {
                "p1": algo_global_this['pin'],
                "p2": algo_global_this['pin']
            },
            "extend": {
                "wd": 0,
                "l": 0,
                "ls": 5,
                "wk": 0,
                "bu1": "0.1.10",
                "bu2": 0,
                "bu3": 38,
                "bu4": 0,
                "bu5": 0
            },
            "pp1": "",
            "w": 2560,
            "h": 1440,
            "ow": 2558,
            "oh": 1398,
            "url": "https://trade.m.jd.com/pay?sceneval=2&scene=jd&isCanEdit=1&EncryptInfo=&Token=&bid=&type=0&lg=0&supm=0&scan_orig=search.1.undefined.undefined.undefinedsearch.2.undefined.undefined&wdref=https%3A%2F%2Fitem.m.jd.com%2Fproduct%2F1887526.html%3Fsceneval%3D2%26jxsid%3D17164281345878329125%26appCode%3Dms0ca95114%26_fd%3Djdm&commlist=1887526,,1,1887526,1,0,0&locationid=1-72-2819-0&jxsid=17164281345878329125&appCode=ms0ca95114#/index",
            "og": "https://trade.m.jd.com",
            "pf": "Win32",
            "pr": 1,
            "re": "",
            "random": random_val,
            "referer": "",
            "v": fv,
            "bu2": "    at https://storage.360buyimg.com/webcontainer/js_security_v3.js:3:7011",
            "canvas": algo_global_this['canvas'],
            "webglFp": algo_global_this['webglFp'],
            "ccn": 12,
            "ai": app_id,
            "fp": fp
        }
        plaintext = json.dumps(plaintext_dict, indent=2, ensure_ascii=False)
        return algo_encrypt_ctx.call('getLastEncryptStr', *(plaintext, algo_global_this['key'], algo_global_this['iv']))

    expandParams = get_env_str(fv, fp, app_id)
    timestamp = int(time.time() * 1000)
    data = {
        "version": version,
        "fp": fp,
        "appId": app_id,
        "timestamp": timestamp,
        "platform": platform,
        "expandParams": expandParams,
        "fv": fv
    }
    data = json.dumps(data, separators=(',', ':'))
    url = "https://cactus.jd.com/request_algo"
    spider_config = {
        'url': url,
        'data': data,
        'proxies': {},
        'headers': headers,
        'timeout': 5,
    }
    response = _request(
        method='POST',
        **spider_config
    )
    data_dict = response.json()
    if data_dict['status'] != 200:
        raise Exception('request_algo 算法获取失败 ！')

    tk = data_dict['data']['result']['tk']
    fp = data_dict['data']['result']['fp']
    algo = data_dict['data']['result']['algo']
    rd = rd_obj.search(algo).group(1)
    algo_type = algo_obj.search(algo).group(1)
    return {
        '_token': tk,
        'rd': rd,
        '_fingerprint': fp,
        'algo_type': algo_type,
    }

def get_h5stv4_7_3(params, global_this):
    """h5st v4.7.3"""
    def get_env_str():
        """各种指纹+AES-CBC 验证ok 魔改版本"""
        # 指纹信息
        random_val = ''.join(random.choices("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-", k=12))
        plaintext_dict = {
            "sua": global_this['sua'],
            "pp": {
                # "p1": global_this['pin'],
                "p2": global_this['pin'],
            },
            "extend": {
                "wd": 0,
                "l": 0,
                "ls": 5,
                "wk": 0,
                "bu1": "0.1.9",
                "bu2": -1,
                "bu3": 88,
                "bu4": 0,
                "bu5": 0
            },
            "random": random_val,
            "v": global_this['version'],
            "fp": global_this['_fingerprint'],
            "bu1": "0.1.8"
        }
        plaintext = json.dumps(plaintext_dict, indent=2, ensure_ascii=False)
        return encrypt_ctx.call('getLastEncryptStr', *(plaintext, global_this['key'], global_this['iv']))

    def my_sha256(encrypt_data, ) -> str:
        """
        md5摘要算法加密
        :return:
        """
        from hashlib import sha256
        obj = sha256()
        obj.update(encrypt_data.encode('utf-8'))
        res = obj.hexdigest()
        return res

    algo_type = global_this['algo_type']
    sorted_params = dict(sorted(params.items(), key=lambda x: x[0]))
    sorted_params['body'] = my_sha256(sorted_params['body'])

    timestamp = int(time.time() * 1e3)
    env_str = get_env_str()
    dt_object = datetime.datetime.fromtimestamp(timestamp // 1000) + datetime.timedelta(milliseconds=timestamp % 1000)
    formatted_time = dt_object.strftime('%Y%m%d%H%M%S') + str(dt_object.microsecond // 1000)[:3]


    data_str = f"{global_this['_token']}{global_this['_fingerprint']}{formatted_time + '78'}{global_this['_appId']}{global_this['rd']}"

    if 'Hmac' in algo_type:
        first_key = hmac_ctx.call(algo_type, *(data_str, global_this['_token']))
    else:
        first_key = hmac_ctx.call(algo_type, data_str)

    mid_str = '&'.join([f'{key}:{sorted_params[key]}' for key in sorted_params])

    second_key = hmac_ctx.call('HmacSHA256', *(mid_str, first_key))
    h5st = ';'.join(
        [
            formatted_time,
            global_this['_fingerprint'],
            global_this['_appId'],
            global_this['_token'],
            second_key,
            global_this['_version'],
            str(timestamp),
            env_str
        ]
    )
    return h5st



# 核心接口 - h5st
@api.route("/h5st", methods=["GET","POST"])
async def h5st(request):
    from sanic import json

    if request.method != "POST":
        return json({
            "code": -1,
            "msg": "failed",
            "data": "请使用POST请求传参！"
        })

    try:
        data_dict = request.json

        params = data_dict['params']

        token_algo = data_dict['token_algo']
        ua = data_dict['ua']
        pin = data_dict['pin']
        _appId = data_dict['_appId']
        _fingerprint = data_dict['_fingerprint']

        global_this = {
            "_version": "4.7",
            "version": "h5_file_v4.7.3",

            "_appId": _appId,
            "_fingerprint": _fingerprint,
            'ua': ua,
            'sua': re.search(r"\((?P<sua>.*?)\)", ua).group('sua'),
            'pin': pin,

            'iv': '0102030405060708',
            'key': "_M6Y?dvfN40VMF[X",

        }
        global_this.update(token_algo)

        data_dict = {
            'h5st': get_h5stv4_7_3(params, global_this)
        }

        return json({
            "code": 0,
            "msg": "success",
            "data": data_dict
        })
    except Exception as error:
        error_data_dict = {
            'error':str(error)
        }
        return json({
            "code": -1,
            "msg": "fail",
            "data": error_data_dict
        })


# 算法更新
@api.route("/update_algo", methods=["GET","POST"])
async def update_algo(request):
    from sanic import json

    if request.method != "POST":
        return json({
            "code": -1,
            "msg": "failed",
            "data": "请使用POST请求传参！"
        })

    try:
        algo_data_dict = request.json
        data_dict = update_algo_4_7(algo_data_dict)

        return json({
            "code": 0,
            "msg": "success",
            "data": data_dict
        })
    except Exception as error:
        error_data_dict = {
            'error':str(error)
        }
        return json({
            "code": -1,
            "msg": "fail",
            "data": error_data_dict
        })